﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Diagnostics;

namespace Snake
{
    class Game
    {
        int width = 30;
        int height = 17;
        int horizontalOffset = 3;
        int verticalOffset = 3;
        private InputHandler _inputHandler = new InputHandler();
        public Random _random = new Random();
        Stopwatch s = Stopwatch.StartNew();
        bool foodNotEaten = true;
        bool endGame = false;
        Direction direction = Direction.Up;

        public void StartGame()
        {
            s.Reset();
            int[,] map = CreateMap();
            int[,] snake = CreateSnake();
            int[] food = CreateFood();

            while (true)
            {
                if (endGame)
                {                   
                    Console.WriteLine("\n            Your Snake is Guf!");
                    Console.ReadKey();
                    break;
                }              
                
                Direction? d= _inputHandler.WaitAndCheckInput(300);
                SetDirection(d);              

                snake = NextPositionOfSnake(map, snake, food, direction);
                ViewOnDisplay(map, snake);
                Console.WriteLine("\n        Time - "+s.ElapsedMilliseconds / 1000);
               
               

                map = CreateMap();

                if (!foodNotEaten)
                {
                    food = CreateFood();
                    foodNotEaten = true;
                }
                if (foodNotEaten)
                map[food[0], food[1]] = (int) Map.Food;

            }
        }

        private void SetDirection(Direction? d)
        {
            if (!d.HasValue)
                return;

            if ((d == Direction.Up && direction == Direction.Down)
                   || (d == Direction.Down && direction == Direction.Up)
                   || (d == Direction.Left && direction == Direction.Right)
                   || (d == Direction.Right && direction == Direction.Left))
            {
                return;
            }

            direction = d.Value;
        }



        public int[,] CreateMap()
        {

            int[,] map = new int[height + verticalOffset, width + horizontalOffset];
            for (int i = 0; i < height + verticalOffset; i++)
            {
                for (int j = 0; j < width + horizontalOffset; j++)
                {
                    if ((i == verticalOffset && j >= horizontalOffset) | (j == horizontalOffset && i >= verticalOffset) |
                        (i == height + verticalOffset - 1 && j >= horizontalOffset) |
                        (j == width + horizontalOffset - 1 && i >= verticalOffset))
                    {
                        map[i, j] = (int)Map.Border;
                        continue;
                    }

                    {
                        map[i, j] = (int)Map.FreeSpace;
                    }
                }
            }

            return map;
        }

        public int[,] CreateSnake( )
        {

            int snakeStartI = _random.Next(verticalOffset + 4, height + verticalOffset - 4);
            int snakeStartJ = _random.Next(horizontalOffset + 4, width + horizontalOffset - 4);
          
            int[,] snake = new int[300, 2];
               
            snake[0, 0] = snakeStartI;
            snake[0, 1] = snakeStartJ;
            snake[1, 0] = snakeStartI + 1;
            snake[1, 1] = snakeStartJ;                 
            snake[2, 0] = snakeStartI + 2;
            snake[2, 1] = snakeStartJ;


            return snake;
        }

        public int[] CreateFood()
        {
            int[] food = {
                             _random.Next(verticalOffset + 1, height + verticalOffset - 1),
                             _random.Next(horizontalOffset + 1, width + horizontalOffset - 1)
                         };

            return food;
            
        }
        

        public int[,] NextPositionOfSnake(int[,] map, int[,] actualPosition, int[] food, Direction direction)
        {
            int[,] nextPosition = new int[300, 2];
            int k = 0;
            for (k=0; k < 299; k++)
            {
                if (actualPosition[k, 0] == 0)
                    break;
                nextPosition[k + 1, 0] = actualPosition[k, 0];
                nextPosition[k + 1, 1] = actualPosition[k, 1];
            }

            switch (direction)
            {
                case Direction.Up:
                    {
                        nextPosition[0, 0] = actualPosition[0, 0] - 1;
                        nextPosition[0, 1] = actualPosition[0, 1];
                        if (map[nextPosition[0, 0], nextPosition[0, 1]] == (int)Map.Border)
                            nextPosition[0, 0] = verticalOffset + height - 2;

                        break;
                    }
                case Direction.Down:
                    {
                        nextPosition[0, 0] = actualPosition[0, 0] + 1;
                        nextPosition[0, 1] = actualPosition[0, 1];
                        if (map[nextPosition[0, 0], nextPosition[0, 1]] == (int)Map.Border)
                            nextPosition[0, 0] = verticalOffset + 1;
                        break;
                    }
                case Direction.Left:
                    {
                        nextPosition[0, 0] = actualPosition[0, 0];
                        nextPosition[0, 1] = actualPosition[0, 1] - 1;
                        if (map[nextPosition[0, 0], nextPosition[0, 1]] == (int)Map.Border)
                            nextPosition[0, 1] = width + horizontalOffset - 2;
                        break;

                    }
                case Direction.Right:
                    {
                        nextPosition[0, 0] = actualPosition[0, 0];
                        nextPosition[0, 1] = actualPosition[0, 1] + 1;
                        if (map[nextPosition[0, 0], nextPosition[0, 1]] == (int)Map.Border)
                            nextPosition[0, 1] = horizontalOffset + 1;
                        break;

                    }

            }
            if (map[nextPosition[0, 0], nextPosition[0, 1]] != (int)Map.Food)
            {
                nextPosition[k, 0] = 0;
                nextPosition[k, 1] = 0;

            }
            else
            {
                map[nextPosition[0, 0], nextPosition[0, 1]] = (int)Map.FreeSpace;
                foodNotEaten = false;
            }
            for (int i = 1; i < 299; i++)
            {
                if (nextPosition[0, 0] == nextPosition[i, 0] && nextPosition[0, 1] == nextPosition[i, 1])
                {
                    endGame = true;
                    break;
                }
            }
           return nextPosition;
       }
        

        public void ViewOnDisplay(int[,] map, int[,] snake)
        {
            for (int i = 0; i < 300; i++)
            {
                if (snake[i,0]==0)
                    break;
                map[snake[i, 0], snake[i, 1]] = (int) Map.Snake;
            }
            Console.Clear();
            Console.WriteLine("***********************SNAKE***********************");
            for (int i = 0; i < map.GetLength(0); i++)
            {
                for (int j = 0; j < map.GetLength(1); j++)
                {
                    switch (map[i,j])
                    {
                        case (int)Map.Border:
                            Console.Write("#");
                            break;
                        case (int)Map.FreeSpace:
                            Console.Write(" ");
                            break;
                        case (int)Map.Snake:
                            Console.Write("o");
                            break;
                        case (int)Map.Food:
                            Console.Write("X");
                            break;
                  
                            
                    }

                }
                Console.Write("\n");
                
            }

        }


    }
}
